`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////Asyncsys Lab////////////////////////////////////////
// Author: Zhenbang Kang
// Email: kangzhb20@lzu.edu.cn
// Create Date: 2022/06/10 
// Module Name: click_control
// Project Name: ac8051 (Asynchronous Click 8051)
// Target Devices: XC7A100TFGG484-2
// Tool Versions: Vivado 2019.1
// Description:IF&ID ADL and EX ADL
// Revision: V2.0
//////////////////////////////////////////////////////////////////////////////////

module click_control(
        rst_n,
        in_R,                       //start
        out_R_icache,               //from  icache
        in_A_icache_click2,         //from  icache
        in_A_dcache_read,           //from  dcache
        out_R_dcache_read,          //from  dcache
        in_A_dcache_write,          //from  dcache
        out_R_dcache_write,         //from  dcache        
        in_A_icache,                //to    icacahe
        out_R_delay_final2,         //to    icache
        out_R_delay_final1,         //to    dcache        
//        in_A_click3,                //to    dcache        
        out_R_delay_final3,         //to    dcache
        out_R_delay5,               //to    ext_sram
        fire_start,
        fire_out_first,
        fire_ext_sram,
        fire_cyc,
        fire_uart,
        fire_tx_end,
        fire_out_second,
        o_second_begin,
        fire_cycsecond,
        fire_rx,
        fire_rx_end           
    );
        input     rst_n;
        input     in_R;                       //start
        input     out_R_icache;               //from  icache
        input     in_A_icache_click2;         //from  icache
        input     in_A_dcache_read;           //from  dcache
        input     out_R_dcache_read;          //from  dcache
        input     in_A_dcache_write;          //from  dcache
        input     out_R_dcache_write;         //from  dcache 
        input     fire_tx_end;       
        output    in_A_icache;                //to    icacahe
        output    out_R_delay_final2;         //to    icache
        output    out_R_delay_final1;         //to    dcache        
//        output    in_A_click3;                //to    dcache        
        output    out_R_delay_final3;         //to    dcache
        output    out_R_delay5;               //to    ext_sram
        output    fire_start;
        output    fire_out_first;
        output    fire_ext_sram;
        output    fire_cyc;
        output    fire_uart;
        output    fire_out_second;
        output    o_second_begin;
        output    fire_cycsecond;
        output    fire_rx;
        input     fire_rx_end;          

wire    rst_n;
wire    in_R;                       //start
(*dont_touch="true"*)wire    out_R_icache;               //from  icache
(*dont_touch="true"*)wire    in_A_icache_click2;         //from  icache
(*dont_touch="true"*)wire    in_A_dcache_read;           //from  dcache
(*dont_touch="true"*)wire    out_R_dcache_read;          //from  dcache
(*dont_touch="true"*)wire    in_A_dcache_write;          //from  dcache
(*dont_touch="true"*)wire    out_R_dcache_write;         //from  dcache        
(*dont_touch="true"*)wire    in_A_icache;                //to    icacahe
(*dont_touch="true"*)wire    out_R_delay_final2;         //to    icache
(*dont_touch="true"*)wire    out_R_delay_final1;         //to    dcache        
//(*dont_touch="true"*)wire    in_A_click3;                //to    dcache        
(*dont_touch="true"*)wire    out_R_delay_final3;         //to    dcache
(*dont_touch="true"*)wire    out_R_delay5;               //to    ext_sram
wire    fire_start;
wire    fire_start_inv;
wire    fire_out_first;
wire    fire_ext_sram;
wire    fire_out_second;
wire    fire_cyc;
wire    fire_tx_end;          

//(*dont_touch="true"*)wire    in_R_note;
//(*dont_touch="true"*)wire    in_R_start;
(*dont_touch="true"*)wire    out_R_start;
(*dont_touch="true"*)wire    in_A_first;
(*dont_touch="true"*)wire    out_R_control;
(*dont_touch="true"*)wire    in_A_sram;
(*dont_touch="true"*)wire    in_A_ex;
(*dont_touch="true"*)wire    out_R_delay_final4;
wire process_req_in;
wire process_req_end;
(*dont_touch="true"*)wire process_req_tmp;
(*dont_touch="true"*)reg process_req_out;
wire fire_end;
wire fire_uart;
(*dont_touch="true"*)wire in_R_inv;
(*dont_touch="true"*)reg cnt_1;
(*dont_touch="true"*)reg cnt_2;
(*dont_touch="true"*)wire out_R_begin;
wire fire_begin;
wire fire_begin_inv;
(*dont_touch="true"*)reg out_A_req;
(*dont_touch="true"*)reg out_A_start;

wire    fire_second;
(*dont_touch="true"*)wire    in_R_second;
(*dont_touch="true"*)wire    o_second_begin;
wire    fire_cycsecond;
wire    fire_rx;
wire    fire_rx_end;

assign in_R_inv = ~in_R;

(* keep_hierarchy = "yes" *)click click_req(  
                                    .in_R(in_R_inv),      
                                    .in_A(),    
                                    .out_R(out_R_start),   
                                    .out_A(out_A_req),   
                                    .fire(fire_start)    
//                                    .rst(rst_n)
                                    );                                    


 always@(posedge fire_start or negedge rst_n)begin
    if(!rst_n)begin
        cnt_1 <= 'b0;
    end else begin
        cnt_1 <= 'b1;
    end
 end
 
 always@(posedge fire_start or negedge rst_n)begin
    if(!rst_n)begin
        cnt_2 <= 'b0;
    end else if(cnt_1==1) begin
        cnt_2 <= 'b1;
    end
 end 
 
assign fire_start_inv = ~fire_start;

always@(posedge fire_start_inv or negedge rst_n)begin
    if(!rst_n)begin
        out_A_req <= 'b0;
    end else begin
        out_A_req <= out_R_start;
    end
end 
 
assign process_req_in =  (fire_start & cnt_2) | process_req_end;
 assign process_req_tmp = ~process_req_out;

 always@(posedge process_req_in or negedge rst_n)begin
    if(!rst_n)begin
        process_req_out <= 'b0;
    end else begin
        process_req_out <= process_req_tmp;
    end
 end
    
(* keep_hierarchy = "yes" *)click_control_first first(
               .rst_n(rst_n),
               .in_R_rst(in_R),
               .in_R(process_req_out),                            //from  CPU 
//               .in_R(in_R_first),                            //from  CPU                
//               .in_A(in_A_first),                           //to    click_start 
               .in_R_icache(out_R_icache),                  //from  icache
               .in_A_icache_click2(in_A_icache_click2),     //from  icache            
               .in_A_icache(in_A_icache),                   //to    icacahe
               .out_R_delay_final2(out_R_delay_final2),     //to    icache
//               .in_A_ex(in_A_ex),                           //from  id/ex
//               .out_R_delay_final4(out_R_delay_final4),     //to    id/ex
               .fire_cyc(fire_cyc),
               .fire_out(fire_out_first),
               .fire_end_second(fire_end),
               .in_R_second(in_R_second),
			   .fire_second(fire_second),
			   .o_second_begin(o_second_begin),
			   .fire_rx_end(fire_rx_end)
    );
    
(* keep_hierarchy = "yes" *)click_control_second  second(
            .rst_n(rst_n),
            .in_R_rst(in_R),
            .in_R(in_R_second),                      //from  if                              
//            .in_A(in_A_ex),                                 //to    if
            .out_R_delay_final1(out_R_delay_final1),        //to    dcache
            .in_A_dcache_read(in_A_dcache_read),            //from  dcache
//            .in_A_click3(in_A_click3),                      //to    dcache
            .out_R_dcache_read(out_R_dcache_read),          //from  dcache
            .out_R_delay_final3(out_R_delay_final3),        //to    dcache
            .in_A_dcache_write(in_A_dcache_write),          //from  dcache
            .out_R_dcache_write(out_R_dcache_write),        //from  dcache
            .out_R_delay5(out_R_delay5),                    //to    ext_sram
            .fire_ext_sram(fire_ext_sram),
            .fire_out(fire_out_second),
            .fire_uart(fire_uart),
            .fire_tx_end(fire_tx_end),
            .fire_end(fire_end),
            .fire_cycsecond(fire_cycsecond),
            .fire_rx(fire_rx),
            .fire_rx_end(fire_rx_end)                      
    );
    
//    assign process_req_end = fire_end & cnt_2;
 assign process_req_end = fire_second & cnt_2;
endmodule
